namespace Sage.Data.Mask
{
    /// <summary>
    /// 数据脱敏核心工具类
    /// </summary>
    /// <remarks>
    /// 提供通用的脱敏处理方法，支持按类型脱敏和自定义规则脱敏。
    /// 作为脱敏功能的统一入口，便于进行批量处理和统一管理。
    /// 与扩展方法配合使用，提供完整的脱敏解决方案。
    /// 所有方法都经过性能优化，适用于高并发和大数据量场景。
    /// </remarks>
    public static class Maskers
    {
        /// <summary>
        /// 根据指定的脱敏类型进行数据脱敏处理。
        /// </summary>
        /// <param name="value">需要脱敏的值。</param>
        /// <param name="maskType">脱敏类型。</param>
        /// <returns>脱敏后的值，如果输入为null或空则根据脱敏类型返回相应结果。</returns>
        public static string? Mask(string? value, MaskType maskType)
        {
            if (string.IsNullOrEmpty(value)) return value;

            return maskType switch
            {
                MaskType.Email => value.MaskEmail(),
                MaskType.Phone => value.MaskPhone(),
                MaskType.IdCard => value.MaskIdCard(),
                MaskType.BankCard => value.MaskBankCard(),
                MaskType.Name => value.MaskName(),
                MaskType.Address => value.MaskAddress(),
                MaskType.Password => value.MaskPassword(),
                MaskType.IpAddress => value.MaskIpAddress(),
                MaskType.CompanyName => value.MaskCompanyName(),
                MaskType.LicensePlate => value.MaskLicensePlate(),
                MaskType.Passport => value.MaskPassport(),
                MaskType.SSN => value.MaskSsn(),
                MaskType.ImAccount => value.MaskImAccount(),
                MaskType.Url => value.MaskUrl(),
                MaskType.BirthDate => value.MaskBirthDate(),
                MaskType.DocumentNumber => value.MaskDocumentNumber(),
                MaskType.CreditCard => value.MaskCreditCard(),
                MaskType.MacAddress => value.MaskMacAddress(),
                MaskType.GpsCoordinates => value.MaskGpsCoordinates(),
                MaskType.Imei => value.MaskImei(),
                MaskType.DriverLicense => value.MaskDriverLicense(),
                MaskType.SerialNumber => value.MaskSerialNumber(),
                MaskType.JwtToken => value.MaskJwtToken(),
                _ => value
            };
        }

        /// <summary>
        /// 通用脱敏方法，根据指定的头尾保留长度进行脱敏。
        /// </summary>
        /// <param name="value">要脱敏的字符串。</param>
        /// <param name="prefixLength">保留头部长度。</param>
        /// <param name="suffixLength">保留尾部长度。</param>
        /// <returns>脱敏后的字符串，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// string text1 = "abcdefghijk";
        /// string masked1 = Maskers.Mask(text1, 2, 2); // 返回 "ab*******jk"
        /// 
        /// string text2 = "12345";
        /// string masked2 = Maskers.Mask(text2, 1, 1); // 返回 "1***5"
        /// 
        /// string text3 = "ABC";
        /// string masked3 = Maskers.Mask(text3, 2, 2); // 返回 "A**"（长度不足时的处理）
        /// 
        /// // 自定义脱敏规则
        /// string sensitive = "sensitive-data-12345";
        /// string custom = Maskers.Mask(sensitive, 3, 5); // 返回 "sen***12345"
        /// 
        /// // 批量自定义脱敏
        /// var customRules = new[]
        /// {
        ///     new { Value = "data1", Prefix = 1, Suffix = 1 },
        ///     new { Value = "data2", Prefix = 2, Suffix = 2 },
        ///     new { Value = "data3", Prefix = 0, Suffix = 4 }
        /// };
        /// 
        /// foreach (var rule in customRules)
        /// {
        ///     var masked = Maskers.Mask(rule.Value, rule.Prefix, rule.Suffix);
        ///     Console.WriteLine(masked);
        /// }
        /// </code>
        /// </example>
        /// <remarks>
        /// 这是一个灵活的通用脱敏方法，可以根据业务需求自定义保留规则：
        /// - 参数验证：负数会被转换为0
        /// - 长度处理：当保留长度超过字符串长度时，会进行智能调整
        /// - 特殊情况：1个字符直接返回*，避免信息泄露
        /// - 兜底处理：参数不合理时返回首字符+*的安全格式
        /// 适用于各种需要自定义脱敏规则的业务场景。
        /// 与预定义的脱敏类型配合使用，提供完整的脱敏解决方案。
        /// 性能优化：使用AsSpan减少字符串分配，优化分支逻辑。
        /// </remarks>
        public static string? Mask(string? value, int prefixLength, int suffixLength)
        {
            if (string.IsNullOrEmpty(value)) return value;

            int len = value.Length;

            // 参数规范化
            prefixLength = Math.Max(0, prefixLength);
            suffixLength = Math.Max(0, suffixLength);

            // 特殊情况快速处理
            if (len == 1) return "*";
            if (prefixLength + suffixLength >= len)
                return string.Concat(value.AsSpan(0, 1), new string('*', len - 1));
            if (prefixLength == 0 && suffixLength == 0)
                return new string('*', len);

            // 边界检查
            if (prefixLength >= len)
                return string.Concat(value.AsSpan(0, len - 1), "*");
            if (suffixLength >= len)
                return string.Concat("*", value.AsSpan(len - 1));

            // 正常脱敏
            int maskLen = len - prefixLength - suffixLength;
            return maskLen <= 0
                ? string.Concat(value.AsSpan(0, 1), new string('*', len - 1))
                : string.Concat(
                    value.AsSpan(0, prefixLength),
                    new string('*', maskLen),
                    value.AsSpan(len - suffixLength, suffixLength)
                );
        }

        /// <summary>
        /// 批量脱敏处理，支持不同字段使用不同的脱敏规则。
        /// </summary>
        /// <param name="data">要脱敏的数据字典，Key为数据值，Value为脱敏类型。</param>
        /// <returns>脱敏后的数据字典。</returns>
        /// <remarks>
        /// 批量处理功能，适用于需要对多个不同类型的敏感数据进行统一脱敏的场景。
        /// 返回脱敏后的结果字典，保持原有的数据结构。
        /// 如果输入数据为null或空，返回空字典。
        /// 性能优化：预分配字典容量，减少内存重新分配。
        /// </remarks>
        public static Dictionary<string, string?> BatchMask(Dictionary<string, MaskType>? data)
        {
            if (data == null || data.Count == 0)
                return [];

            var result = new Dictionary<string, string?>(data.Count);

            foreach (var item in data)
            {
                result[item.Key] = Mask(item.Key, item.Value);
            }

            return result;
        }

        /// <summary>
        /// 智能批量脱敏，自动识别数据类型并应用相应的脱敏规则。
        /// </summary>
        /// <param name="values">要脱敏的数据列表。</param>
        /// <returns>脱敏后的数据列表。</returns>
        /// var sensitiveData = new[]
        /// {
        ///     "john@example.com",      // 自动识别为邮箱
        ///     "13812345678",           // 自动识别为手机号
        ///     "110101199001011234",    // 自动识别为身份证
        ///     "6222081234567890123",   // 自动识别为银行卡
        ///     "some other text"        // 通用文本脱敏
        /// };
        /// var maskedResults = Maskers.SmartBatchMask(sensitiveData);
        /// <remarks>
        /// 使用智能识别算法自动判断数据类型并应用相应的脱敏规则。
        /// 适用于混合数据类型的批量脱敏处理。
        /// 识别准确性有限，建议在已知数据类型时使用BatchMask方法。
        /// 性能优化：使用ToList()预分配容量，避免多次扩容。
        /// </remarks>
        public static List<string?> SmartBatchMask(IEnumerable<string?>? values)
        {
            if (values == null) return [];

            // 性能优化：如果是ICollection，预分配容量
            if (values is ICollection<string?> collection)
            {
                var result = new List<string?>(collection.Count);
                foreach (var value in collection)
                {
                    result.Add(value.SmartMask());
                }
                return result;
            }

            return [.. values.Select(v => v.SmartMask())];
        }

        /// <summary>
        /// 并行批量脱敏处理，适用于大数据量场景。
        /// </summary>
        /// <param name="data">要脱敏的数据字典。</param>
        /// <returns>脱敏后的数据字典。</returns>
        /// <remarks>
        /// 使用并行处理提高大数据量脱敏的性能。
        /// 适用于数据量超过1000条的批量脱敏场景。
        /// 小数据量时建议使用BatchMask方法，避免并行开销。
        /// </remarks>
        public static Dictionary<string, string?> ParallelBatchMask(Dictionary<string, MaskType>? data)
        {
            if (data == null || data.Count == 0)
                return [];

            var result = new Dictionary<string, string?>(data.Count);
            var lockObject = new object();

            Parallel.ForEach(data, item =>
            {
                var maskedValue = Mask(item.Key, item.Value);
                lock (lockObject)
                {
                    result[item.Key] = maskedValue;
                }
            });

            return result;
        }
    }
}
